package com.eternal.log.model;

import android.app.Application;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.paging.DataSource;
import androidx.paging.PagedList;
import androidx.paging.PositionalDataSource;
import androidx.annotation.NonNull;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.view.View;

import com.eternal.base.LivePagedBuilder;
import com.eternal.base.LogService;
import com.eternal.base.concat.LogExtra;
import com.eternal.base.data.LogRepository;
import com.eternal.base.data.ble.BleStatue;
import com.eternal.base.database.entity.Log;
import com.eternal.base.global.ActivityEvent;
import com.eternal.base.global.BluetoothKey;
import com.eternal.framework.bus.Messenger;
import com.eternal.framework.component.BaseViewModel;
import com.eternal.framework.utils.GsonUtils;
import com.eternal.framework.utils.KLog;
import com.eternal.framework.utils.RxUtils;
import com.eternal.framework.utils.SPUtils;
import com.eternal.log.LogFragment;
import com.eternal.log.R;
import com.eternal.widget.ColorSpan;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.schedulers.Schedulers;

/**
 * Created by Administrator
 * On 2020/5/12
 * Description:
 * @author Administrator
 */
public class LogModel extends BaseViewModel {
    public LogModel(@NonNull Application application) {
        super(application);
        show.setValue(true);
    }

    public static final Spannable SHOW;
    public static final Spannable HIDE;
    static {
        ColorSpan span=new ColorSpan();
        SHOW=new SpannableString("SHOW FILTERS");
        SHOW.setSpan(span, 0, SHOW.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        HIDE=new SpannableString("HIDE FILTERS");
        HIDE.setSpan(span, 0, HIDE.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    public String mac;
    private byte port;
    private LogRepository repository;

    public MutableLiveData<Boolean> show=new MutableLiveData<>();
    public MutableLiveData<Boolean> auto=new MutableLiveData<>();
    public MutableLiveData<Boolean> schedules=new MutableLiveData<>();
    public MutableLiveData<Boolean> timeOn=new MutableLiveData<>();
    public MutableLiveData<Boolean> timeOff=new MutableLiveData<>();
    public MutableLiveData<Boolean> cycle=new MutableLiveData<>();
    public MutableLiveData<Boolean> alarms=new MutableLiveData<>();
    public MutableLiveData<Boolean> alert=new MutableLiveData<>();
    public MutableLiveData<Boolean> automation=new MutableLiveData<>();
    public LiveData<PagedList<Log>> logs;

    public View.OnClickListener onName=new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(show.getValue()){
                show.setValue(false);
            }else{
                show.setValue(true);
            }
        }
    };

    public View.OnClickListener onFilter=new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int id = v.getId();
            if (id == R.id.tv_auto_tigger) {
                changeState(auto);
            } else if (id == R.id.tv_schedules) {
                changeState(schedules);
            } else if (id == R.id.tv_time_to_on) {
                changeState(timeOn);
            } else if (id == R.id.tv_time_to_off) {
                changeState(timeOff);
            } else if (id == R.id.tv_cycles) {
                changeState(cycle);
            } else if (id == R.id.tv_alarm) {
                changeState(alarms);
            } else if (id == R.id.tv_alerts) {
                changeState(alert);
            } else if (id == R.id.tv_automations) {
                changeState(automation);
            }
        }
    };

    private void changeState(MutableLiveData<Boolean> data){
        data.setValue(!data.getValue());
        Messenger.getDefault().sendNoMsg(LogFragment.REFRESH_LOG);
    }

    public void refresh(){
        logs=getSource();
        LogService.getInstance().addRefresh(mac, port);
    }

    public void init(LogRepository repository, final String mac, byte port){
        this.mac=mac;
        this.port = port;
        this.repository=repository;

        all();
        String typesString = SPUtils.getInstance().getString(ActivityEvent.SHARED_PREFERENCES_KEY_LOG_CHECKED_TYPES+mac + (port==0?"":port));
        String modelsString = SPUtils.getInstance().getString(ActivityEvent.SHARED_PREFERENCES_KEY_LOG_CHECKED_MODELS+mac + (port==0?"":port));
//        String[] strings = new String[2];
//        strings[0] = typesString;
//        strings[1] = modelsString;
        List<Byte> types;
//        String typesString = strings[0];
//        String modelsString = strings[1];
        if (TextUtils.isEmpty(typesString)) {
            Byte [] allType = {1,2,3};
            types = Arrays.asList(allType);
        } else {
            types = GsonUtils.getList(typesString,Byte.class);
        }
        if (types != null) {
            if(types.contains((byte) 1)){
                automation.setValue(true);
            }
            if(types.contains((byte) 2)){
                alarms.setValue(true);
            }
            if(types.contains((byte) 3)){
                alert.setValue(true);
            }
        }

        List<Byte> models;
        if (TextUtils.isEmpty(modelsString)) {
            Byte [] allModel = {3,4,5,6,7};
            models = Arrays.asList(allModel);
        } else {
            models = GsonUtils.getList(modelsString,Byte.class);
        }
        if (models != null) {
            if(models.contains((byte) 3)){
                auto.setValue(true);
            }
            if(models.contains((byte) 4)){
                timeOn.setValue(true);
            }
            if(models.contains((byte) 5)){
                timeOff.setValue(true);
            }
            if(models.contains((byte) 6)){
                cycle.setValue(true);
            }
            if(models.contains((byte) 7)){
                schedules.setValue(true);
            }
        }
        logs=getSource();

    }

//    private void getLogs() {
//        BleStatue bleStatue = repository.getConnect(mac);
//        if (bleStatue.getType() == BluetoothKey.DEVICE_TYPE_A || bleStatue.getType() == BluetoothKey.DEVICE_TYPE_B) {
//            repository.refreshLog(bleStatue);
//        } else if (bleStatue.getType()== BluetoothKey.DEVICE_TYPE_E) {
//            repository.refreshELog(bleStatue,port);
//        } else {
//            repository.refreshCLog(bleStatue);
//        }
//        repository.refreshLog(bleStatue);
//    }

    private LiveData<PagedList<Log>> getSource(){
        List<Byte> types = new ArrayList<>(3);
        if(automation.getValue()){
            types.add((byte) 1);
        }
        if(alarms.getValue()){
            types.add((byte) 2);
        }
        if(alert.getValue()){
            types.add((byte) 3);
        }
        List<Byte> models=new ArrayList<>(5);
        if(auto.getValue()){
            models.add((byte) 3);
        }
        if(timeOn.getValue()){
            models.add((byte) 4);
        }
        if(timeOff.getValue()){
            models.add((byte) 5);
        }
        if(cycle.getValue()){
            models.add((byte) 6);
        }
        if(schedules.getValue()){
            models.add((byte)7);
        }
        final String modelsString = GsonUtils.toJson(models);
        final String typesString = GsonUtils.toJson(types);
        Single.create(new SingleOnSubscribe<Boolean>() {
            @Override
            public void subscribe(@io.reactivex.annotations.NonNull SingleEmitter<Boolean> emitter) throws Exception {
                SPUtils.getInstance().put(ActivityEvent.SHARED_PREFERENCES_KEY_LOG_CHECKED_MODELS+mac+(port==0?"":port), modelsString);
                SPUtils.getInstance().put(ActivityEvent.SHARED_PREFERENCES_KEY_LOG_CHECKED_TYPES+mac+(port==0?"":port), typesString);
            }
        }).subscribeOn(Schedulers.io()).ignoreElement().subscribe();

        if(models.size()==0&&types.size()==0){
            return new LivePagedBuilder<>(new EmptyFactory(),
                    new PagedList.Config.Builder()
                            .setPageSize(12)
                            .setInitialLoadSizeHint(0)
                            .setEnablePlaceholders(false)
                            .build()).build();
        }

        return new LivePagedBuilder<>(repository.getLogFactory(mac, port, types, models),
                new PagedList.Config.Builder()
                        .setPageSize(15)
                        .setInitialLoadSizeHint(45)
                        .setEnablePlaceholders(false)
                        .build()).build();
    }

    private void all(){
        auto.setValue(false);
        schedules.setValue(false);
        timeOn.setValue(false);
        timeOff.setValue(false);
        cycle.setValue(false);
        alarms.setValue(false);
        alert.setValue(false);
        automation.setValue(false);
    }

    public void resetTime(){
        repository.resetTime(mac,port)
                .compose(RxUtils.bindToLifecycle(getLifecycleProvider()))
                .subscribeOn(Schedulers.io())
                .subscribe();
    }

    public Single<LogExtra> initAdapter(){
        return repository.getExtra(mac);
    }

    public Single<LogExtra> getExtra(){
        return repository.getExtra(mac);
    }

    static class EmptyFactory extends DataSource.Factory<Integer, Log> {
        static final List<Log> empty=new ArrayList<>();
        @Override
        public DataSource<Integer, Log> create() {
            return new PositionalDataSource<Log>() {
                @Override
                public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<Log> callback) {
                    callback.onResult(empty, params.requestedStartPosition);
                }

                @Override
                public void loadRange(@NonNull LoadRangeParams params, @NonNull LoadRangeCallback<Log> callback) {
                    callback.onResult(empty);
                }
            };
        }
    }
}
